package util;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.util.Scanner;

import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.GroupLayout.Group;

/**
 * acts as a gui console, pipes the standard output and prints it to a text area,
 * includes an exit button for quick shutdown
 * @author jack
 *
 */
public class ConsoleMonitor extends JFrame implements Runnable
{
	private static final long serialVersionUID = 1L;
	private JTextArea ta = new JTextArea();
	private JScrollPane sp;
	/**
	 * determines whether the scroll pane should jump to the bottom upon text appending
	 */
	private boolean jumpUponAppend = false;
	
	/**
	 * creates a new console, the frame has no title
	 */
	public ConsoleMonitor()
	{
		this("");
	}
	/**
	 * creates a new console
	 * @param consoleName the title of the frame the console is created in
	 */
	public ConsoleMonitor(String consoleName)
	{
		super(consoleName);
		sp = new JScrollPane(ta);
		JButton exit = new JButton("Exit");
		exit.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e)
			{
				System.exit(0);
			}
		});
		JCheckBox autoScroll = new JCheckBox("Jump Upon Append: ");
		autoScroll.addItemListener(new ItemListener(){
			public void itemStateChanged(ItemEvent e)
			{
				jumpUponAppend = e.getStateChange() == ItemEvent.SELECTED;
			}
		});
		/*JPanel p = new JPanel();
		p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
		p.add(sp);
		p.add(exit);*/
		
		JPanel p = new JPanel();
		GroupLayout g = new GroupLayout(p);
		p.setLayout(g);
		g.setAutoCreateGaps(true);
		g.setAutoCreateContainerGaps(true);
		//ta.setPreferredSize(new Dimension(160*6, 100*6));
		
		sp.setPreferredSize(new Dimension(160*6, 100*6));
		exit.setPreferredSize(new Dimension(50, 10));
		g.setVerticalGroup(g.createSequentialGroup()
				.addComponent(sp)
				.addGroup(g.createParallelGroup(GroupLayout.Alignment.BASELINE, true)
						.addComponent(exit)
						.addComponent(autoScroll))
		);
		g.setHorizontalGroup(g.createParallelGroup(GroupLayout.Alignment.LEADING, true)
				.addComponent(sp)
				.addGroup(g.createSequentialGroup()
						.addComponent(exit)
						.addComponent(autoScroll))
		);
		
		add(p);
		//setSize(160*6, 100*6); //maintains rough golden ratio
		pack();
		setLocationRelativeTo(null);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
		
		Thread t = new Thread(this);
		t.setDaemon(true);
		t.start();
		//waits until the monitoring thread has been started before continuing
		synchronized(this)
		{
			try
			{
				wait();
			}
			catch(InterruptedException e){}
		}
	}
	public void run()
	{
		Thread outReader = new Thread(new Runnable(){
			public void run()
			{
				try
				{
					PipedOutputStream pos = new PipedOutputStream();
					PrintStream pps = new PrintStream(pos);
					System.setOut(pps);
					PipedInputStream pis = new PipedInputStream(pos);
					Scanner s = new Scanner(pis);
					while(s.hasNextLine())
					{
						//System.out.println(s.nextLine());
						ta.append(s.nextLine()+"\n");
						if(jumpUponAppend && sp.getVerticalScrollBar() != null)
						{
							//sp.getViewport().setViewPosition(new Point(0, sp.getViewport().getHeight()));
							sp.getVerticalScrollBar().setValue(sp.getVerticalScrollBar().getMaximum());
						}
					}
					System.out.println("asd");
				}
				catch(IOException e)
				{
					e.printStackTrace();
				}
			}
		});
		outReader.setDaemon(true);
		outReader.start();
		Thread errReader = new Thread(new Runnable(){
			public void run()
			{
				try
				{
					PipedOutputStream pos = new PipedOutputStream();
					PrintStream pps = new PrintStream(pos);
					System.setErr(pps);
					PipedInputStream pis = new PipedInputStream(pos);
					Scanner s = new Scanner(pis);
					while(s.hasNextLine())
					{
						//System.out.println(s.nextLine());
						ta.append(s.nextLine()+"\n");
						if(jumpUponAppend && sp.getVerticalScrollBar() != null)
						{
							//sp.getViewport().setViewPosition(new Point(0, sp.getViewport().getHeight()));
							sp.getVerticalScrollBar().setValue(sp.getVerticalScrollBar().getMaximum());
						}
					}
					System.out.println("asd");
				}
				catch(IOException e)
				{
					e.printStackTrace();
				}
			}
		});
		errReader.setDaemon(true);
		errReader.start();
		synchronized(this)
		{
			notify();
		}
	}
	public static void main(String[] args)
	{
		new ConsoleMonitor();
	}
}
